package com.beiding.jsonanalyzer.querylink;

import com.beiding.jsonanalyzer.common.ConsumerWithRuntimeException;
import com.beiding.jsonanalyzer.flow.BranchNode;
import com.beiding.jsonanalyzer.flow.Flow;
import com.beiding.jsonanalyzer.flow.branchevents.FlowEnd;
import com.beiding.jsonanalyzer.flow.flowevents.BatchEndEvent;
import com.beiding.jsonanalyzer.flow.flowevents.BatchStartEvent;
import com.beiding.jsonanalyzer.flow.flowevents.DataNodeEvent;
import com.beiding.jsonanalyzer.visit.VisitAble;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 执行结果
 *
 * @author 丁常磊
 * @date 2022/4/24 14:35
 */

public class QueryLinkNodeResult<W> {

    private Logger logger = Logger.getLogger(QueryLinkNodeResult.class.getName());

    /**
     * 返回的结果是一个分支集合
     */
    private VisitAble<BranchNode<W>> branches;

    private Flow flow;

    public QueryLinkNodeResult(VisitAble<BranchNode<W>> branches, Flow flow) {
        this.branches = branches;
        this.flow = flow;
    }

    public VisitAble<BranchNode<W>> getBranches() {
        return branches;
    }

    public Flow getFlow() {
        return flow;
    }

    /**
     * 阻塞当前线程,搜集所有结果,当执行完全后再最终返回结果
     *
     * @return
     */
    public List<Row<W>> get() {

        List<Row<W>> list = Collections.synchronizedList(new ArrayList<>());

        Exception[] error = new Exception[]{null};

        //创建一个异步任务
        FutureTask<List<Row<W>>> futureTask = new FutureTask<>(() -> {

            if (error[0] != null) {
                throw error[0];
            }

            return list;
        });

        //但执行完成返回最终结果
        onEnd(flowEnd -> {
            error[0] = flowEnd.getException();
            futureTask.run();
        });

        //对每个结果追加
        forEach(list::add);
        try {
            return futureTask.get();
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException(e);
        }

    }

    /**
     * 结束后可判断是否出错结束
     *
     * @param callback
     * @return
     */
    public QueryLinkNodeResult<W> onEnd(ConsumerWithRuntimeException<FlowEnd> callback) {
        flow.addListener(FlowEnd.class, event -> {
            try {
                callback.accept(event);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        return this;
    }

    /**
     * 异步结果
     */
    public void forEach(ConsumerWithRuntimeException<Row<W>> consumer) {
        branches.visit(b -> {

            //空白,不做任何处理
            b.onDataEvent(BatchStartEvent.eventType(), event -> {
            });

            //数据事件
            b.onDataEvent(DataNodeEvent.eventType(), event -> {
                try {
                    consumer.accept(new Row<>(event.getData(), b));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });

            //空白,不做任何处理
            b.onDataEvent(BatchEndEvent.eventType(), event -> {
            });
        });
    }

}
